unit SmallStruct.Controller.TSSController;

interface

uses
  Classes,
  SmallStruct.Core,
  SmallStruct.Core.TSSObjectContext,
  SmallStruct.Controller,
  SmallStruct.Form.TSSFrame,
  SmallStruct.ActionView,
  Controls,
  Forms,
  SmallStruct.Form.TSSPanel,
  SmallStruct.Controller.TSSControllerNavigator;

type
  TSSController = class(TSSFrame, ISSController)
  private
    _ActionViewContainer: ISSObjectContainer;
    _ControllerNavigator: ISSControllerNavigator;
  public { ISSRuntimeObject }
    procedure InitObject; override;
  protected
    function FindActionView(const AActionViewName: string): ISSActionView;
    function GetActionActionViewName: string;
    function GetSystemObject: ISSSystemObject;
    function RequestAction(const AActionViewName, AActionCaption: string): Boolean;
    procedure AppendActionView(const AActionViewName: string);
    procedure DeleteActionView(const AActionViewName: string);
  protected
    function GetActionName(const AActionViewName, AActionCaption: string): string;
    procedure InitControllerNavigator;
    procedure DisplayActionView(const AActionViewName: string);
    procedure FreeActionView; overload;
    procedure FreeActionView(AActionView: ISSActionView); overload;
    function CreateActionView(const AActionViewName: string): ISSActionView;
    function FilterAction(const AActionViewName, AActionCaption: string): Boolean;
    function PerformAction(const AActionViewName, AActionCaption: string): Boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  TSSControllerContext = class(TSSObjectContext, ISSControllerContext)
  private
    _SystemObject: ISSSystemObject;
  public
    function GetSystemObject: ISSSystemObject;
    procedure SetSystemObject(ASystemObject: ISSSystemObject);
  end;

implementation

uses
  SysUtils,
  SmallStruct.ActionView.TSSActionView,
  SmallStruct.Configuration,
  SmallStruct.Core.TSSObjectContainer,
  SmallStruct.BusinessObject,
  SmallStruct.Action,
  SmallStruct.Action.TSSAction;

{$R *.dfm}

{ TSSController }

procedure TSSController.InitControllerNavigator;
var
  ObjectInstance: TWinControl;
  Context: TSSControllerNavigatorContext;
begin
  ObjectInstance := TWinControlClass((GetSystemObject.GetClassTable as ISSClassTable).QueryClass(SS_CONTROLLER_NAVIGATOR_NAME)).Create(Self);
  (ObjectInstance as IUnknown).QueryInterface(ISSControllerNavigator, _ControllerNavigator);

  Context := TSSControllerNavigatorContext.Create(nil);
  Context.SetController(Self);

  _ControllerNavigator.SetContext(Context);
  _ControllerNavigator.InitObject;

  ObjectInstance.Parent := Self;
  ObjectInstance.Height := 32;
  ObjectInstance.Align := alTop;
end;

procedure TSSController.InitObject;
begin
  InitControllerNavigator;
end;

function TSSController.PerformAction(const AActionViewName, AActionCaption: string): Boolean;
var
  Action: ISSAction;
  ActionContext: TSSActionContext;
  ActionViewActionConfiguration: ISSActionViewActionConfiguration;
  ResponseActionView: ISSActionView;
  ActionName: string;
begin
  Action := ((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_ACTION_FACTORY) as ISSActionFactory).GetAction(GetActionName(AActionViewName, AActionCaption));
  ActionContext := Action.GetContext.GetObjectInstance as TSSActionContext;
  ActionContext.SetController(Self);
  ActionContext.SetRequestView((_ActionViewContainer.GetObject(AActionViewName) as ISSActionView).GetView);
  ActionViewActionConfiguration := ((_ActionViewContainer.GetObject(AActionViewName) as ISSActionView).GetContext.GetConfiguration as ISSActionViewConfiguration).GetActionConfiguration.GetObject(AActionCaption) as ISSActionViewActionConfiguration;

  if ActionViewActionConfiguration.GetRequestActionViewName <> '' then
  begin
    ResponseActionView := CreateActionView(ActionViewActionConfiguration.GetRequestActionViewName);
    ActionContext.SetResponseView(ResponseActionView.GetView);
  end;

  try
    try
      Result := Action.Perform;
      if Result and (ActionViewActionConfiguration.GetRequestActionViewName <> '') then
        _ActionViewContainer.AppendObject(ActionViewActionConfiguration.GetRequestActionViewName, ResponseActionView.GetObjectInstance);
    except
      on E: Exception do
      begin
        if Assigned(ResponseActionView) then
          FreeActionView(ResponseActionView);
        Result := False;
        raise;
      end;
    end;
  finally
    ((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_ACTION_FACTORY) as ISSActionFactory).FreeAction(Action);
  end;
end;

procedure TSSController.AppendActionView(const AActionViewName: string);
var
  ActionView: ISSActionView;
begin
  if _ActionViewContainer.FindObject(AActionViewName) >= 0 then
    DisplayActionView(AActionViewName)
  else
  begin
    ActionView := CreateActionView(AActionViewName);

    if _ActionViewContainer.GetCount > 0 then
    begin
      if (ActionView.GetContext.GetConfiguration as ISSActionViewConfiguration).GetType = ssavtDialog then
        (_ActionViewContainer.GetObject(_ActionViewContainer.GetCount - 1) as ISSActionView).DisableActionView
      else
        (_ActionViewContainer.GetObject(_ActionViewContainer.GetCount - 1) as ISSActionView).CloseActionView;
    end;

    _ActionViewContainer.AppendObject(AActionViewName, ActionView.GetObjectInstance);
    DisplayActionView(AActionViewName);
  end;
end;

constructor TSSController.Create(AOwner: TComponent);
begin
  inherited;
  _ActionViewContainer := TSSObjectContainer.Create(Self);
end;

function TSSController.CreateActionView(const AActionViewName: string): ISSActionView;
var
  ActionViewContext: TSSActionViewContext;
  ActionViewFactory: ISSActionViewFactory;
begin
  ActionViewFactory := (GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_ACTIONVIEW_FACTORY_NAME) as ISSActionViewFactory;
  Result := ActionViewFactory.GetActionView(AActionViewName);
  ActionViewContext := Result.GetContext.GetObjectInstance as TSSActionViewContext;
  ActionViewContext.SetController(Self);
  Result.SetContext(ActionViewContext);

  (Result.GetObjectInstance as TWinControl).Parent := Self;
end;

procedure TSSController.DeleteActionView(const AActionViewName: string);
var
  Instance: ISSActionView;
  Index: Integer;
begin
  if _ActionViewContainer.GetCount < 2 then
    Exit;

  Index := _ActionViewContainer.FindObject(AActionViewName);
  Instance := _ActionViewContainer.GetObject(Index) as ISSActionView;

  _ActionViewContainer.RemoveObject(Index);
  Instance.CloseActionView;

  ((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_ACTIONVIEW_FACTORY_NAME) as ISSActionViewFactory).FreeActionView(Instance);

  if Index > 0 then
    DisplayActionView(_ActionViewContainer.GetObjectName(Index - 1));
end;

destructor TSSController.Destroy;
begin
  FreeActionView;
  _ActionViewContainer.ReleaseObjectInstance;
  inherited;
end;

procedure TSSController.DisplayActionView(const AActionViewName: string);
var
  ActionView: ISSActionView;
begin
  if _ActionViewContainer.FindObject(AActionViewName) >= 0 then
    ActionView := _ActionViewContainer.GetObject(AActionViewName) as ISSActionView;
  ActionView.EnableActionView;
  ActionView.DisplayActionView;
  (ActionView.GetObjectInstance as TWinControl).Parent := Self;
  _ControllerNavigator.SetTitle((ActionView.GetContext.GetConfiguration as ISSActionViewConfiguration).GetActionViewCaption, nil);
end;

function TSSController.FilterAction(const AActionViewName, AActionCaption: string): Boolean;
var
  ActionConfiguration: ISSActionViewActionConfiguration;
  Filter: ISSActionFilter;
  Index: Integer;
begin
  Result := True;

  ActionConfiguration := (((_ActionViewContainer.GetObject(AActionViewName) as ISSActionView).GetContext.GetConfiguration as ISSActionViewConfiguration).GetActionConfiguration).GetObject(AActionCaption) as ISSActionViewActionConfiguration;

  for Index := 0 to ActionConfiguration.GetActionFilterName.Count - 1 do
  begin
    Filter := ((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_BUSINESS_OBJECT_FACTORY_NAME) as ISSBusinessObjectFactory).GetBusinessObject(ActionConfiguration.GetActionFilterName.Strings[Index]) as ISSActionFilter;
    try
      try
        Result := Filter.Filter(AActionViewName, AActionCaption, ActionConfiguration.GetRequestActionViewName);
        if not Result then
          Exit;
      except
        on E: Exception do
        begin
          Result := False;
          raise;
        end;
      end;
    finally
      ((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_BUSINESS_OBJECT_FACTORY_NAME) as ISSBusinessObjectFactory).FreeBusinessObject(Filter);
    end;
  end;
end;

function TSSController.FindActionView(const AActionViewName: string): ISSActionView;
begin
  Result := _ActionViewContainer.GetObject(AActionViewName) as ISSActionView;
end;

procedure TSSController.FreeActionView(AActionView: ISSActionView);
begin
  (((GetSystemObject.GetGlobalObjectTable as ISSObjectContainer).GetObject(SS_ACTIONVIEW_FACTORY_NAME)) as ISSActionViewFactory).FreeActionView(AActionView);
end;

procedure TSSController.FreeActionView;
begin
  while _ActionViewContainer.GetCount > 0 do
  try
    FreeActionView(_ActionViewContainer.GetObject(0) as ISSActionView);
  finally
    _ActionViewContainer.RemoveObject(0);
  end;
end;

function TSSController.GetSystemObject: ISSSystemObject;
begin
  Result := (GetContext as ISSControllerContext).GetSystemObject;
end;

function TSSController.GetActionActionViewName: string;
var
  Index: Integer;
  ActionView: TSSActionView;
begin
  for Index := _ActionViewContainer.GetCount - 1 downto 0 do
  begin
    ActionView := _ActionViewContainer.GetObject(Index) as TSSActionView;

    if ActionView.Visible then // and ActionView.Enabled then
    begin
      Result := ((ActionView as ISSActionView).GetContext.GetConfiguration as ISSActionViewConfiguration).GetActionViewName;
      Exit;
    end;
  end;
end;

function TSSController.GetActionName(const AActionViewName, AActionCaption: string): string;
var
  ActionView: ISSActionView;
  ActionConfiguration: ISSObjectContainer;
begin
  ActionView := _ActionViewContainer.GetObject(AActionViewname) as ISSActionView;
  ActionConfiguration := ((ActionView.GetContext as ISSActionViewContext).GetConfiguration as ISSActionViewConfiguration).GetActionConfiguration;
  Result := (ActionConfiguration.GetObject(AActionCaption) as ISSActionViewActionConfiguration).GetActionName;
end;

function TSSController.RequestAction(const AActionViewName, AActionCaption: string): Boolean;
var
  ActionConfiguration: ISSActionViewActionConfiguration;
begin
  Result := FilterAction(AActionViewName, AActionCaption);

  if not Result then
    Exit;
  if PerformAction(AActionViewName, AActionCaption) then
  begin
    ActionConfiguration := ((_ActionViewContainer.GetObject(AActionViewName) as ISSActionView).GetContext.GetConfiguration as ISSActionViewConfiguration).GetActionConfiguration.GetObject(AActionCaption) as ISSActionViewActionConfiguration;

    if ActionConfiguration.IsAutoClose then
      DeleteActionView(AActionViewName)
    else if ActionConfiguration.GetRequestActionViewName <> '' then
      DisplayActionView(ActionConfiguration.GetRequestActionViewName);
  end;
end;

{ TSSControllerContext }

function TSSControllerContext.GetSystemObject: ISSSystemObject;
begin
  Result := _SystemObject;
end;

procedure TSSControllerContext.SetSystemObject(ASystemObject: ISSSystemObject);
begin
  _SystemObject := ASystemObject;
end;

end.
